﻿//QuikDdeServer.cs
//Copyright (c) 2013 StockSharp LLC, all rights reserved.
//This code module is part of StockSharp library.
//This code is licensed under the GNU GENERAL PUBLIC LICENSE Version 3.
//See the file License.txt for the license details.
//More info on: http://stocksharp.com

namespace StockSharp.Quik
{
	using System;
	using System.Collections.Generic;
	using System.IO;
	using System.Threading;

	using Ecng.ComponentModel;
	using Ecng.Common;

	using NDde.Server;

	sealed class QuikDdeServer : DdeServer
	{
		private readonly ManualResetEvent _registerWaitHandle = new ManualResetEvent(false);
		private Timer _adviseTimer;
		private readonly EventDispatcher _dispather;

		public QuikDdeServer(string service)
			: base(service)
		{
			_dispather = new EventDispatcher(error => Error.SafeInvoke(error));
		}

		public event Action<string, IList<IList<object>>> Poke;
		public event Action<Exception> Error;

		public void Start()
		{
			Exception error = null;

			var regLock = new object();

			lock (regLock)
			{
				ThreadingHelper
					.Thread(() =>
					{
						try
						{
							Register();

							lock (regLock)
								Monitor.Pulse(regLock);

							_registerWaitHandle.WaitOne();
						}
						catch (Exception ex)
						{
							lock (regLock)
								Monitor.Pulse(regLock);

							error = ex;
						}
					})
					.Name("Dde thread")
					.Launch();

				Monitor.Wait(regLock);
			}

			if (error != null)
				throw new InvalidOperationException("Ошибка запуска DDE сервера.", error);

			// Create a timer that will be used to advise clients of new data.
			_adviseTimer = ThreadingHelper.Timer(() =>
			{
				try
				{
					// Advise all topic name and item name pairs.
					Advise("*", "*");
				}
				catch (Exception ex)
				{
					Error.SafeInvoke(ex);
				}
			})
			.Interval(TimeSpan.FromSeconds(1));
		}

		protected override PokeResult OnPoke(DdeConversation conversation, string item, byte[] data, int format)
		{
			_dispather.Add(() =>
			{
				var rows = DdeSerializer.Deserialize(data.To<Stream>());
				Poke.SafeInvoke(conversation.Topic, rows);
			}, conversation.Topic);

			return PokeResult.Processed;
		}

		protected override void Dispose(bool disposing)
		{
			_dispather.Dispose();

			if (disposing)
			{
				if (!_adviseTimer.IsNull())
					_adviseTimer.Dispose();
				_registerWaitHandle.Set();
			}

			base.Dispose(disposing);
		}
	}
}